Factory Pattern
2 min readRapid overview
Factory Pattern
TL;DR
Centralize creation of objects (like API handlers or executors) based on configuration or environment.
How it works
🧩 Example — Trading platform executor factory
public interface ITradeExecutor
{
void Execute(Order order);
}
public class Mt4Executor : ITradeExecutor
{
public void Execute(Order order) =>
Console.WriteLine($"[MT4] Executing {order.Symbol}");
}
public class Mt5Executor : ITradeExecutor
{
public void Execute(Order order) =>
Console.WriteLine($"[MT5] Executing {order.Symbol}");
}
public static class ExecutorFactory
{
public static ITradeExecutor Create(string platform) => platform switch
{
"MT4" => new Mt4Executor(),
"MT5" => new Mt5Executor(),
_ => throw new ArgumentException("Unknown platform")
};
}
// --- Usage ---
var platform = "MT5";
var executor = ExecutorFactory.Create(platform);
executor.Execute(new Order { Symbol = "USDJPY", Amount = 5000 });
✅ Why it matters:
- Simplifies platform switching (MT4, MT5, FIX, cTrader).
- New platforms require no refactor — just a new class and switch entry.
Quick recall Q&A
Q: When should you use a Factory pattern in .NET services? A: When object creation depends on runtime context (config, tenant, instrument) and you want to isolate creation logic from consumers. Factories prevent scattered
new calls and keep construction consistent.Q: How does DI interact with factories? A: You can register implementations in DI and inject
Func<Key, ITradeExecutor> or an IExecutorFactory that resolves services by key. This keeps factories composable with scoped dependencies.Q: How do you avoid giant switch statements as platforms grow? A: Use a dictionary of delegates, reflection-based registration, or DI
IServiceProvider lookups keyed by platform. Alternatively, combine with the Strategy pattern so each executor registers itself.Q: What’s the benefit of abstract factories? A: When you need to create families of related objects (e.g., executor + validator + serializer per platform), an abstract factory ensures compatible components are produced together.
Q: How do factories aid testing? A: Tests can inject fake factories returning mock executors, isolating code under test without hitting real integrations. It also simplifies verifying that the correct executor is chosen for a scenario.
Q: How do you handle configuration-driven factories? A: Load mappings from configuration or feature flags, then let the factory instantiate types via DI. This enables runtime toggles (e.g., route VIP tenants to a premium executor) without code changes.
Q: When is the factory pattern overkill? A: When only two concrete types exist and creation logic is trivial. Start simple, and introduce a factory once switching logic repeats or needs shared validation/logging.
Q: How do you ensure factories remain SRP-compliant? A: Keep them focused on creation. Any orchestration, validation, or logging should be delegated to other components or decorators so factories don't become god objects.
Q: Can factories return async results? A: Yes—define methods returning
Task<T> if creation involves I/O (e.g., pulling secrets). Just ensure callers understand the lifecycle and avoid blocking .Result.Q: How do you register factories in DI? A: Register each concrete type and a factory delegate:
services.AddTransient<ExecutorFactory>(); or services.AddSingleton<Func<string, ITradeExecutor>>(provider => key => provider.GetRequiredKeyedService<ITradeExecutor>(key));.